package de.unistuttgart.iaas.interaction.mail.util;

import java.io.*;
import java.sql.*;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeUtility;
import javax.xml.validation.*;
import javax.xml.transform.*;
import javax.xml.transform.stream.StreamSource;

import org.xml.sax.SAXException;

/**
 * This class defines all used methods in this project
 * getResponseTemplate(), mailClassIdentifier(),registerSubjectCheck(),saveFile(), getText(),isValidResponse()
 * 
 * @author Lina Sun
 *
 */
public class CommonTools 
{
	private static final String RESPONSE = "RESPONSE";
	private static final String REGISTER = "REGISTER";
	private static final String NOTIFICATION = "NOTIFICATION";
	private static final String UNKNOWN = "UNKNOWN";
	private static final String SCHEMA_LANGUAGE = "http://www.w3.org/2001/XMLSchema";

/**
 * The method extracts the part of attachment in a message object.
 * @param part
 * @return
 * @throws Exception
 */
	public static Part getAttachment(Part part)throws Exception
	{
		Part attachment = null;
		
		String contenttype = part.getContentType();
		int nameindex = contenttype.indexOf("name");
		boolean conname = false;
		if(nameindex!=-1)
		{
			conname= true;
			
		}
		if(part.isMimeType("text/plain")&&conname)
		{			
			return part;
//			attachment = (BodyPart)part.getContent();
//			if(attachment!=null)
//			{
//				return attachment;
//			}
		}else if (part.isMimeType("text/html") && conname)
		{
			return part;
//			attachment = (BodyPart)part.getContent();
//			if(attachment!=null)
//			{
//				return attachment;
//			}
			
		}else if(part.isMimeType("multipart/*"))
		{
			Multipart multipart =(Multipart)part.getContent();
			int counts = multipart.getCount();
				for (int i = 0; i < counts; i++) {
					attachment = getAttachment(multipart.getBodyPart(i));
					if(attachment!=null)
					{
						return attachment;
					}
				}
		}
		return attachment;
			
	}
	/**
	 * The method extracts the content of the mail in a message object.
	 * @param part
	 * @return
	 * @throws Exception
	 */
	
	public static String getMessage(Part part)throws Exception
	{
		String mail_message = "";
		
		String contenttype = part.getContentType();
		int nameindex = contenttype.indexOf("name");
		boolean conname = false;
		if(nameindex!=-1)
		{
			conname= true;
			
		}
		if(part.isMimeType("text/plain")&&!conname)
		{
			mail_message = (String)part.getContent();
			if(!mail_message.equals(""))
			{
				return mail_message;
			}
		}else if (part.isMimeType("text/html") && !conname)
		{
			mail_message = (String)part.getContent();
			if(!mail_message.equals(""))
			{
				return mail_message;
			}
			
		}else if(part.isMimeType("multipart/*"))
		{
			Multipart multipart =(Multipart)part.getContent();
			int counts = multipart.getCount();
			System.out.println(counts);
			
			for (int i = 0; i < counts; i++) {
				mail_message = getMessage(multipart.getBodyPart(i));
				if(!mail_message.equals(""))
				{
					return mail_message;
				}
			}

		}
		return mail_message;
			
	}
	
	/**
	 * This method transforms a xml schema String to a xml String
	 * @param xsdStr
	 * @return xml string
	 */
	public static String xsdToXml(ConfigFileHandler config,String xsdStr)
	{
		String xmlStr = "<response>";
		String nameList = "";
		String tag = config.getTag();
		int i =0;
		
		String xsdElement = xsdStr.substring(xsdStr.indexOf("<sequence>")+10,xsdStr.indexOf("</sequence>"));
		
		while(xsdElement.indexOf("element name=")!=-1)
		{		
			nameList= nameList + xsdElement.substring(xsdElement.indexOf("name=")+6, xsdElement.indexOf("type")-2)+"|";
			xsdElement = xsdElement.substring(xsdElement.indexOf("/>")+2);
		}
		String[] name= (nameList.substring(0, nameList.lastIndexOf("|"))).split("\\|");
		String simpleType = xsdStr.substring(xsdStr.indexOf("<simpleType"));
		for(i = 0; i<name.length; i++)
		{			
			xmlStr = xmlStr+ "<"+tag+":"+name[i]+">";
			
			String temp = simpleType.substring(simpleType.indexOf("<simpleType name='"+ name[i]));
			temp = temp.substring(temp.indexOf("<restriction"), temp.indexOf("</restriction>"));
			String type = temp.substring(temp.indexOf("base")+6, temp.indexOf(">")-1);
			String min = "";
			String max = "";
			String enumeration ="";
			if(temp.indexOf("minInclusive")!=-1)
			{
				min = temp.substring(temp.indexOf("minInclusive")+20, temp.indexOf("</minInclusive")-2);
			}
			if(temp.indexOf("maxInclusive")!=-1)
			{
				max = temp.substring(temp.indexOf("maxInclusive")+20, temp.indexOf("</maxInclusive")-2);
			}
			while(temp.indexOf("enumeration")!=-1)
			{
				
				enumeration = enumeration+temp.substring(temp.indexOf("enumeration")+19, temp.indexOf("</enumeration")-2)+"|";
				temp = temp.substring(temp.indexOf("</enumeration>")+14);
				
			}
			if(!enumeration.equals(""))
			{
				System.out.println(enumeration.length()-1);
				xmlStr = xmlStr + enumeration.substring(0, enumeration.length()-1)+"</"+tag+":"+name[i]+">";
			}else if((min.equals("")&&max.equals(""))||(min.equals(max)))
			{
				xmlStr = "false response template.";
				
			}else
			{
				xmlStr = xmlStr + "["+min+"-"+max+"("+type+")]"+"</"+tag+":"+name[i]+">";
			}
		}
		
		return xmlStr+"</response>";
	}
	/**
	 * This method extracts the format of response from input message and transforms this format.
	 * @param responseTemplate -- xml schema
	 * @return String
	 */
	public static String getResponseTemplate(String responseTemplate, ConfigFileHandler config)
	{
		String responseTemplateString="";
		String wsResponseTemp = "";
		String wsResponseTempError = "wsResponseTempError";
		String name = "";
		String type = "";
		String enumeration = "";
		String min ="";
		String max = "";
		int responseNum = 0;
		responseTemplateString = "<element name='response'><complexType><sequence>";
				
		responseTemplate= responseTemplate.replaceAll("\t", "").replaceAll("\n", "");
		String responseTemplateCopy = responseTemplate;
		
		while(responseTemplate.indexOf("<wsResponse>")!=-1)
		{
			int a = responseTemplate.indexOf("</wsResponse>");
			wsResponseTemp = responseTemplate.substring(12, a);
			responseTemplate = responseTemplate.substring(a+13);
			
			if(wsResponseTemp.indexOf("<name>")==-1)
			{
				responseTemplateString=wsResponseTempError;
				return responseTemplateString;
			}else
			{
				name = wsResponseTemp.substring(wsResponseTemp.indexOf("<name>")+6, wsResponseTemp.indexOf("</name>"));
				responseTemplateString = responseTemplateString + "<element name='"+ name +"' type='"+config.getTag()+":" + name +"'/>";
			}
		}
		responseTemplateString = responseTemplateString+"</sequence></complexType></element>";
		
		while(responseTemplateCopy.indexOf("<wsResponse>")!=-1)
		{
			
			int a = responseTemplateCopy.indexOf("</wsResponse>");
			wsResponseTemp = responseTemplateCopy.substring(12, a);
			responseTemplateCopy = responseTemplateCopy.substring(a+13);
			
			
			if(wsResponseTemp.indexOf("<type>")==-1)
			{
				responseTemplateString=wsResponseTempError;
				return responseTemplateString;
			}else
			{
				name = wsResponseTemp.substring(wsResponseTemp.indexOf("<name>")+6, wsResponseTemp.indexOf("</name>"));
				type = wsResponseTemp.substring(wsResponseTemp.indexOf("<type>")+6, wsResponseTemp.indexOf("</type>"));
				responseTemplateString = responseTemplateString + "<simpleType name='"+ name +"'><restriction base='"+type+"'>";
				if(wsResponseTemp.indexOf("<enumeration>")!=-1)
				{
					enumeration = wsResponseTemp.substring(wsResponseTemp.indexOf("<enumeration>")+13, wsResponseTemp.indexOf("</enumeration>"));
					String[] e = enumeration.split("\\|");
					int enumLength = e.length;
					for(int n = 0; n<enumLength; n++)
					{
						responseTemplateString = responseTemplateString+"<enumeration value='"+ e[n]+"'></enumeration>";
					}					
				}
				if(wsResponseTemp.indexOf("<min>")!=-1 && wsResponseTemp.indexOf("</min>")!=wsResponseTemp.indexOf("<min>")+5)
				{
					min = wsResponseTemp.substring(wsResponseTemp.indexOf("<min>")+5, wsResponseTemp.indexOf("</min>"));
					responseTemplateString = responseTemplateString+"<minInclusive value='"+min+"'></minInclusive>";
				}
				if(wsResponseTemp.indexOf("<max>")!=-1 && wsResponseTemp.indexOf("</max>")!=wsResponseTemp.indexOf("<max>")+5)
				{
					max = wsResponseTemp.substring(wsResponseTemp.indexOf("<max>")+5, wsResponseTemp.indexOf("</max>"));
					responseTemplateString = responseTemplateString+"<maxInclusive value='"+max+"'></maxInclusive>";
				}
				
				responseTemplateString = responseTemplateString+"</restriction></simpleType>";

			}
		}
		
		return responseTemplateString;
	}
//	public static String getResponseTemplate(responseTemplate responseTemplate)
//	{
//		String responseTemplateString="";
//		String wsResponseTemp = "";
//		String wsResponseTempError = "wsResponseTempError";
//		String name = "";
//		String type = "";
//		String enumeration = "";
//		String min ="";
//		String max = "";
//		int responseNum = 0;
//
//		responseNum = responseTemplate.getWsResponse().size();
//		responseTemplateString = "<element name='response'><complexType><sequence>";
//		
//		for(int i =0; i<responseNum; i++)
//		{
//			wsResponseTemp = responseTemplate.getWsResponse().get(i).toString();
//			if(wsResponseTemp.indexOf("<name>")==-1)
//			{
//				responseTemplateString=wsResponseTempError;
//				return responseTemplateString;
//			}else
//			{
//				name = wsResponseTemp.substring(wsResponseTemp.indexOf("<name>")+6, wsResponseTemp.indexOf("</name>"));
//				responseTemplateString = responseTemplateString + "<element name='"+ name +"' type='tns:" + name +"'/>";
//			}
//			
//		}
//		responseTemplateString = responseTemplateString+"</sequence></complexType></element>";
//
//		for(int j=0;j<responseNum; j++)
//		{
//			wsResponseTemp = responseTemplate.getWsResponse().get(j).toString();
//			if(wsResponseTemp.indexOf("<type>")==-1)
//			{
//				responseTemplateString=wsResponseTempError;
//				return responseTemplateString;
//			}else
//			{
//				name = wsResponseTemp.substring(wsResponseTemp.indexOf("<name>")+6, wsResponseTemp.indexOf("</name>"));
//				type = wsResponseTemp.substring(wsResponseTemp.indexOf("<type>")+6, wsResponseTemp.indexOf("</type>"));
//				responseTemplateString = responseTemplateString + "<simpleType name='"+ name +"'><restriction base='"+type+"'>";
//				if(wsResponseTemp.indexOf("<enumeration>")!=-1)
//				{
//					enumeration = wsResponseTemp.substring(wsResponseTemp.indexOf("<enumeration>")+13, wsResponseTemp.indexOf("</enumeration>"));
//					String[] e = enumeration.split("\\|");
//					int enumLength = e.length;
//					for(int n = 0; n<enumLength; n++)
//					{
//						responseTemplateString = responseTemplateString+"<enumeration value='"+ e[n]+"'></enumeration>";
//					}					
//				}
//				if(wsResponseTemp.indexOf("<min>")!=-1  )
//				{
//					min = wsResponseTemp.substring(wsResponseTemp.indexOf("<min>")+5, wsResponseTemp.indexOf("</min>"));
//					responseTemplateString = responseTemplateString+"<minInclusive value='"+min+"'></minInclusive>";
//				}
//				if(wsResponseTemp.indexOf("<max>")!=-1 )
//				{
//					max = wsResponseTemp.substring(wsResponseTemp.indexOf("<max>")+5, wsResponseTemp.indexOf("</max>"));
//					responseTemplateString = responseTemplateString+"<maxInclusive value='"+max+"'></maxInclusive>";
//				}
//				
//				responseTemplateString = responseTemplateString+"</restriction></simpleType>";
//
//			}
//		}
	
//		if(responseNum==1)
//		{
//			responseTemplateString = "<response>\n";
//			wsResponseTemp = responseTemplate.getWsResponse().get(0).toString();
//			if(wsResponseTemp.indexOf("<name>")==-1||wsResponseTemp.indexOf("<type>")==-1)
//			{
//				responseTemplateString=wsResponseTempError;
//				return responseTemplateString;
//			}else
//			{
//				name = wsResponseTemp.substring(wsResponseTemp.indexOf("<name>")+6, wsResponseTemp.indexOf("</name>"));
//				type = wsResponseTemp.substring(wsResponseTemp.indexOf("<type>")+6, wsResponseTemp.indexOf("</type>"));
//			}
//			if(wsResponseTemp.indexOf("<enumeration>")!=-1 )
//			{
//				enumeration = wsResponseTemp.substring(wsResponseTemp.indexOf("<enumeration>")+13, wsResponseTemp.indexOf("</enumeration>"));
//			}
//			if(wsResponseTemp.indexOf("<min>")!=-1 )
//			{
//				min = wsResponseTemp.substring(wsResponseTemp.indexOf("<min>")+5, wsResponseTemp.indexOf("</min>"));
//			}
//			if(wsResponseTemp.indexOf("<max>")!=-1 )
//			{
//				max = wsResponseTemp.substring(wsResponseTemp.indexOf("<max>")+5, wsResponseTemp.indexOf("</max>"));
//			}
//			responseTemplateString = responseTemplateString + "<element name ='"+ name+"'>";
//			
//			if(!enumeration.equals(""))
//			{
//				responseTemplateString = responseTemplateString + enumeration;
//			}else
//			{
//				
//				if(max.equalsIgnoreCase(min))
//				{
//					responseTemplateString = responseTemplateString +min+"-"+max+"("+type+")";
//				}
//			}
//			responseTemplateString = responseTemplateString + "</element>\n";
//			
//		}else
//		{
//			responseTemplateString = "<responses>\n";
//			
//			
//			for(int i =0; i<responseNum; i++)
//			{
//				wsResponseTemp = responseTemplate.getWsResponse().get(i).toString();
//				if(wsResponseTemp.indexOf("<name>")==-1||wsResponseTemp.indexOf("<type>")==-1)
//				{
//					responseTemplateString=wsResponseTempError;
//					return responseTemplateString;
//				}else
//				{
//					name = wsResponseTemp.substring(wsResponseTemp.indexOf("<name>")+6, wsResponseTemp.indexOf("</name>"));
//					type = wsResponseTemp.substring(wsResponseTemp.indexOf("<type>")+6, wsResponseTemp.indexOf("</type>"));
//				}
//				if(wsResponseTemp.indexOf("<enumeration>")!=-1 )
//				{
//					enumeration = wsResponseTemp.substring(wsResponseTemp.indexOf("<enumeration>")+13, wsResponseTemp.indexOf("</enumeration>"));
//				}
//				if(wsResponseTemp.indexOf("<min>")!=-1 )
//				{
//					min = wsResponseTemp.substring(wsResponseTemp.indexOf("<min>")+5, wsResponseTemp.indexOf("</min>"));
//				}
//				if(wsResponseTemp.indexOf("<max>")!=-1 )
//				{
//					max = wsResponseTemp.substring(wsResponseTemp.indexOf("<max>")+5, wsResponseTemp.indexOf("</max>"));
//				}
//
//				responseTemplateString = responseTemplateString + "<element name ='"+ name+"'>";
//				if(!enumeration.equals(""))
//				{
//					responseTemplateString = responseTemplateString + enumeration;
//				}else
//				{
//					
//					if(max!= min)
//					{
//						responseTemplateString = responseTemplateString +"["+min+"-"+max+"("+type+")]";
//					}
//				}
//				responseTemplateString = responseTemplateString + "</element>\n";
//			}
//		}
//		if(responseNum==1)
//		{
//			responseTemplateString = responseTemplateString + "</response>\n";
//			
//		}else
//		{
//			responseTemplateString = responseTemplateString + "</responses>\n";
//		}
//		
//		return responseTemplateString;
//	}

	/**
	 * This method determines the value of parameter mail_class(RESPONSE, REGISTER, UNKNOWN).
	 * @param conn
	 * @param oneMail
	 * @param adminAdress
	 * @param config
	 * @return
	 */	
	public static String mailClassIdentifier(Connection conn, Message oneMail, String adminAdress, ConfigFileHandler config)
	{
		String mailClass="";
		
		try{
			String from=((InternetAddress)oneMail.getFrom()[0]).getAddress();  
			String subject = oneMail.getSubject();
			
			if(from.equalsIgnoreCase(adminAdress))
			{
				mailClass = NOTIFICATION;
				
			}else if(registerSubjectCheck(subject))
			{
				mailClass = REGISTER;
			}else
			{
				if((subject.indexOf("RE:")!=-1||subject.indexOf("Re:")!=-1||subject.indexOf("re:")!=-1||subject.indexOf("AW:")!=-1)&&(subject.indexOf("Mail-ID:")!=-1))
				{
					Statement statement = conn.createStatement();
					ResultSet rs = statement.executeQuery("select id from maildb."+ config.getTable_mailregister()+" where mailaddress='"+ from+"'");
					if(rs.next())
					{
						mailClass = RESPONSE;
					}else
					{
						mailClass = UNKNOWN;
					}
				}else
				{
					mailClass = UNKNOWN;
				}
			}
		}catch(Exception e)
		{
			//Error
			System.out.println("Error in mailClassIdentifier()");
		}
		
		return mailClass;
	}
	
	/**
	 * This method determines whether a mail is a register-mail according to its subject.
	 * 
	 * @param subject
	 * @return
	 */
	public static boolean registerSubjectCheck(String subject)
	{
		if(subject.indexOf("register") != -1)
		{
			return true;
		}
		else if(subject.indexOf("regist") != -1)
		{
			return true;
		}
		else if(subject.indexOf("egister")!= -1)
		{
			return true;
		}
		else if(subject.indexOf("rgister") != -1)
		{
			return true;
		}
		else if(subject.indexOf("reister") != -1)
		{
			return true;
		}
		else if(subject.indexOf("regster") != -1)
		{
			return true;
		}
		else if(subject.indexOf("regiter")!= -1)
		{
			return true;
		}
		else if(subject.indexOf("regiser") != -1)
		{
			return true;
		}
		else if(subject.indexOf("ergister") != -1)
		{
			return true;
		}
		else if(subject.indexOf("rgeister") != -1)
		{
			return true;
		}
		else if(subject.indexOf("reigster")!= -1)
		{
			return true;
		}
		else if(subject.indexOf("regsiter") != -1)
		{
			return true;
		}
		else if(subject.indexOf("regitser") != -1)
		{
			return true;
		}
		else if(subject.indexOf("regisetr") != -1)
		{
			return true;
		}
		else if(subject.indexOf("regis")!= -1)
		{
			return true;
		}
		else
		{
			return false;
		}
	}

	/**
	 * This method gets the attachmentsdata from the database. 
	 * According to the filename and filepath this data will be stored in the local.
	 * @param filePath
	 * @param content
	 * @throws Exception
	 */
	public static void saveFile(String filePath, Blob content) throws Exception 
	{  
        FileOutputStream fos = null;  
        BufferedOutputStream bos = null;  
        InputStream is = null;  
        BufferedInputStream bis = null;  
        try {  
            File file = new File(filePath);  
             fos = new FileOutputStream(file);  
             bos = new BufferedOutputStream(fos);  
             is = content.getBinaryStream();  
             bis = new BufferedInputStream(is);  
             int b1 = 0;  
             while ((b1 = bis.read()) != -1) {  
                 bos.write(b1);  
                 bos.flush();  
             }  
        } catch (Exception e) {  
             throw e;  
		         } finally {  
            if(is!=null){  
                 is.close();  
            }  
             if (bis != null) {  
                 bis.close();  
             }  
             if (fos != null) {  
                 fos.close();  
             }  
             if (bos != null) {  
                 bos.close();  
             }  
         }  
     }  
	
    /**
     * This method returns the primary text content of the message.
     * @param p -- message part
     * 
     */
    public static String getText(Part p) throws
                MessagingException, IOException {
        if (p.isMimeType("text/*")) {
            String s = (String)p.getContent();
            return s;
        }

        if (p.isMimeType("multipart/alternative")) {
            // prefer html text over plain text
            Multipart mp = (Multipart)p.getContent();
            String text = null;
            for (int i = 0; i < mp.getCount(); i++) {
                Part bp = mp.getBodyPart(i);
                if (bp.isMimeType("text/plain")) {
                    if (text == null)
                        text = getText(bp);
                    continue;
                } else if (bp.isMimeType("text/html")) {
                    String s = getText(bp);
                    if (s != null)
                        return s;
                } else {
                    return getText(bp);
                }
            }
            return text;
        } else if (p.isMimeType("multipart/*")) {
            Multipart mp = (Multipart)p.getContent();
            for (int i = 0; i < mp.getCount(); i++) {
                String s = getText(mp.getBodyPart(i));
                if (s != null)
                    return s;
            }
        }
        return null;
    }
    /**
     * This method gets the format of response from the database.
     * @param res
     * @param conn
     * @return response
     * @throws Exception
     */
	public static String getResponse(ArrayList res) throws Exception
	{
		String response =(String)res.get(7);
		response = response.replaceAll("\r", "").replace("\n", "").replace(" ", "");
		if(!response.equals(""))
		{
			if(response.indexOf("<response>")!=-1 && response.indexOf("</response>")!=-1)
			{
				response = response.substring(response.indexOf("<response>")+10,response.indexOf("</response>"));
			}else
			{
				response = "";
			}
		}
		return response;
	}
	/**
	 * This method determines whether a response is valid or not.
	 * @param response
	 * @param resTemplate
	 * @return isValidResponse
	 */
	public static boolean isValidResponse(ConfigFileHandler config, String xmlStr, String xsdStr)
	{
		boolean isValidResponse = false;
		xmlStr = config.getXmlHeader()+xmlStr+config.getXmlFoot();
		xsdStr = config.getXsdHeader()+xsdStr + config.getXsdFoot();
		
		SchemaFactory factory = SchemaFactory.newInstance(SCHEMA_LANGUAGE);
		Reader xmlReader = new BufferedReader(new StringReader(xmlStr));
		Reader xsdReader = new BufferedReader(new StringReader(xsdStr));
	
		try
		{
			Source xsdSource = new StreamSource(xsdReader);
			
			Schema schema = factory.newSchema(xsdSource);
			Validator validator = schema.newValidator();
			Source xmlSource = new StreamSource(xmlReader);
			validator.validate(xmlSource);
			isValidResponse = true;
			
			return isValidResponse;
			
		}catch(Exception ex)
		{
			return isValidResponse;
		}
		
	}
}
